//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "XYmdm.h"

#define PRTCOM(x)// x;

extern void InitElrUser();
extern int elr_usb_close( void );
extern int printk(const char *fmt, ...);
extern void *memcpy(void *dest, const void *src, int n);
extern unsigned int ElrUDCWrite(char *pTxBuffer, unsigned int BufLen);
extern int WriteKernel();

extern int g_bWrite;

#define KERN_BUF_BASE 0xA0000000
#define KENN_BUF_OFF  0x00020000
#define CMD_LENGTH    0x08
#define CMD_SERIAL    0x06
char kCmd[2][CMD_LENGTH + 1] = { "KERNEL00\0",//DOWNLOAD KERNEL IMAGE TO RAM
                    "KERNEL01\0",//DOWNLOAD KERNEL IMAGE TO DOC
                    };
int ReceiveFile(char *bufbase, int offset)
{
    char *pData;
    int pos = 0, err = 0;
    unsigned int bRead;
    char *kBase = 0;//Memory address base

    XYM_PKG XymPkg;
    P_XYM_PKG pXPacket = &XymPkg;
    pData = ((P_BLK_STR)pXPacket->PacketData)->Data;

    XYmodemInit();//Init XYmodem protocol
    RECV_INIT(YMDM);

    pXPacket->PacketStatus = PK_NONE;
    pXPacket->PacketDataLen = 0;
    pXPacket->ActionStatus = AC_NONE;

    do {
        Read((unsigned char*)pXPacket, sizeof(XYM_PKG), &bRead);
        if (PK_VALIDDATA == pXPacket->PacketStatus) {
//            PRTCOM(printk("PK_VALIDDATA pXPacket->PacketDataLen %d\n", pXPacket->PacketDataLen));
            if (0 != kBase) {
                memcpy((void*)(kBase + pos), (void*)pData, pXPacket->PacketDataLen);
                pos += pXPacket->PacketDataLen;
//                PRTCOM(printk("kBase + pos = %08x\r", kBase + pos));
                pXPacket->ActionStatus = AC_ACCEPT;
            }
            else {
                err = XmErrSys;
                goto RECV_ERR;
            }
        }
        else if (PK_FILEINFO == pXPacket->PacketStatus) {
//            PRTCOM(printk("PK_FILEINFO pXPacket->PacketDataLen %d\n", pXPacket->PacketDataLen));

            if (0 != kBase) {
                kBase = 0;
                pos = 0;
            }
            if (pData[0] == '\0') {/* last file */
                RECV_ACCEPT();
                goto RECV_ERR;
            }

            kBase = (char*)(bufbase + offset);
//            PRTCOM(printk("Kernel Buffer Base %08x Postion %08x\n", kBase, pos));
            pXPacket->ActionStatus = AC_YMD1STPK;
        }
        else if (PK_CANCEL == pXPacket->PacketStatus) {
            err = 0;
            goto RECV_ERR;
        }
    } while (1);

RECV_ERR:
    if (err) {
        Cancel();
    }
    if (0 != kBase) {
        kBase = 0;
        pos = 0;
    }
    if (pXPacket) {
        pXPacket = 0;
    }
    return err;
}

extern int MyStrCmp(const char *s1, const char *s2, int maxlen);
extern unsigned int ElrUDCWrite(char *pTxBuffer, unsigned int BufLen);
extern unsigned int ElrUDCRead(char *pRxBuffer, unsigned int Bufflen);

int WaitForCmd()
{
    char rBuf[128];
    unsigned int ret, idx = 0;
    ElrUDCWrite("**USE ToRAM OR ToDOC Transfer Image!", 36);
    while (1) {
        ret = ElrUDCRead(rBuf+idx, 1);
        if (ret) {
            //ElrUDCWrite(rBuf+idx, 1);
            idx++;
        }
        if (idx) {
            if (idx <= CMD_SERIAL) {
                if (MyStrCmp((const char *)rBuf, (const char *)kCmd[0], idx)) {
                    PRTCOM(printk("Expect Download Kernel Image Command Serials\n"));
                }
                else {
                    PRTCOM(printk("Unexpect Cmd, idx %02d %s\n", idx, rBuf));
                    idx = 0;
                }
            }
            else if (idx >= CMD_LENGTH) {
                if (MyStrCmp((const char *)rBuf, (const char *)kCmd[0], CMD_LENGTH)) {
                    PRTCOM(printk("Expect Cmd Download Kernel Image To RAM %s\n", kCmd[0]));
                    break;
                }
                else if (MyStrCmp((const char *)rBuf, (const char *)kCmd[1], CMD_LENGTH)) {
                    PRTCOM(printk("Expect Cmd Download Kernel Image To DOC %s\n", kCmd[1]));
                    g_bWrite = 1;
                    break;
                }
                else {
                    PRTCOM(printk("Unkonwn Receive Cmd %s kCmd1 %s kCmd2 %s\n", rBuf, kCmd[0], kCmd[1]));
                    return 1;
                }
            }
        }
    }
    return 0;
}

int UsbDownloadImageEx()
{
    int err;
    PRTCOM(printk("Usb download kernel image ...\n"));
    InitElrUser();
    msleep(1000);
    err = WaitForCmd();
    if (err) {
        PRTCOM(printk("Unexpect Command Received!\n"));
        return 0;//
    }
    PRTCOM(printk("Expect Command Received!\n"));
    PRTCOM(printk("Start Receive Kernel Image ...\n"));
    err = ReceiveFile((char*)KERN_BUF_BASE, KENN_BUF_OFF);
    PRTCOM(printk("Kernel Image Receive "));
    elr_usb_close();
    if (err) {
        PRTCOM(printk("Failed!\n"));
        return 0;//Receive Failed
    }
    PRTCOM(printk("Succeeded!\n"));
    if (g_bWrite) {
        PRTCOM(printk("Write Kernel Image ... "));
        WriteKernel();
        PRTCOM(printk("Completed!\n"));
    }
    return 1;//Receive Succeeded
}
